package com.pason.onlineshop.mainshop.functionaltest.framework;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.StringUtils;
import org.openqa.selenium.WebDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.pason.onlineshop.mainshop.util.EnvironmentUtil;


// http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/chrome/ChromeDriver.html
public class WebDriverContext {

    protected static final Logger logger = LoggerFactory.getLogger(WebDriverContext.class);

    public static final String CHROME = "CHROME";
    public static final String MAVEN = "MAVEN";
    public static final String REMOTE = "REMOTE";
    private static final ThreadLocal<WebDriverContext> webDriverContextHolder = new ThreadLocal<WebDriverContext>();

    private WebDriver webDriver;
    private Browser browser;
    private String webDriverType;
    private String serverHostName;
    private int serverPort;

    // Only to be called from WebDriverTest
    static Browser getBrowser() {
        return instance().browser;
    }

    public static String getServerHostName() {
        return instance().serverHostName;
    }

    public static int getServerPort() {
        return instance().serverPort;
    }

    public static String getWebDriverType() {
        return instance().webDriverType;
    }

    private static synchronized void configureInstance(final WebDriverContext instance) {
        System.setProperty("application.environment", "dev_");
        instance.webDriverType = getEnvironmentBrowserType();
        instance.serverHostName = serverHost(instance.webDriverType);
        instance.serverPort = EnvironmentUtil.getHttpPort();

        instance.webDriver = WebDriverFactory.createWebDriver(instance.webDriverType);
        instance.webDriver.manage().timeouts().implicitlyWait(Browser.DEFAULT_WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
        instance.webDriver.manage().timeouts().setScriptTimeout(Browser.AJAX_MAX_WAIT_TIMEOUT_MILLI_SECONDS, TimeUnit.MILLISECONDS);
        try {
            instance.webDriver.manage().timeouts().pageLoadTimeout(Browser.MAX_WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
        } catch (Exception ex) {
            // ignore
        }

        instance.browser = new Browser(instance.webDriver, instance.webDriverType, instance.serverHostName, instance.serverPort);
    }

    static void createInstance() {
        WebDriverContext instance = new WebDriverContext();
        configureInstance(instance);
        instance.registerBrowserShutdownHook();
        webDriverContextHolder.set(instance);
    }

    private static String getEnvironmentBrowserType() {
        String browserType = CHROME;

        if (MAVEN.equalsIgnoreCase(EnvironmentUtil.getBuildType())) {
            browserType = REMOTE;
        }

        String envBrowserType = EnvironmentUtil.getWebDriverType();

        if (!StringUtils.isEmpty(envBrowserType)) {
            browserType = envBrowserType;
        }
        return browserType;
    }

    private static WebDriverContext instance() {
        if (webDriverContextHolder.get() == null) {
            try {
                createInstance();
            } catch (Exception e) {
                throw new RuntimeException("Application startup failed");
            }
        }
        return webDriverContextHolder.get();
    }

    private static String serverHost(final String webDriverType) {
        String host;

        if (REMOTE.equalsIgnoreCase(webDriverType)) {
            try {
                host = InetAddress.getLocalHost().getHostAddress();

            } catch (UnknownHostException e) {
                throw new RuntimeException(e);
            }
        } else {
            host = EnvironmentUtil.getHostName();
        }
        return host;
    }

    private void registerBrowserShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                shutdownBrowser();
            }
        }));
    }

    public static synchronized void shutdownBrowser() {
        final WebDriverContext webDriverContext = webDriverContextHolder.get();
        if (webDriverContext != null) {
            try {
                webDriverContext.webDriver.quit();
            } catch (Exception e) {
                // ignore
            }
            try {
                // Give the browser a chance to recover
                Thread.sleep(2000);
            } catch (Exception e) {
                // ignore
            }
            webDriverContextHolder.set(null);
        }
    }
}